#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<time.h>
#include<fstream>
#include<unordered_map>
#include<fcntl.h>
#include<boost/algorithm/string.hpp>
#include<jsoncpp/json/json.h>

/*利用宏来调用:[时间戳][日志级别][行数][文件名][DEBUG信息]*/

#define LOG(LEVEL, STR) (Log(#LEVEL, STR, __LINE__, __FILE__))
/*日志的级别信息*/
enum info{
       INFO,
       WARNING,
       ERROR,
       FATAL
};
/*获取时间戳*/
inline static long long Timemap() {
       time_t _timemap = time(NULL);
       return _timemap;
}
/*打印日志*/
inline static void Log(const std::string& info, const std::string& s, int line, const std::string& filename) {
#ifndef DEBUGLOG 
       std::cerr<<"[" << Timemap() << "]" << "[" << info << "][" << line << "]" << "[" << filename <<"]" << "[" << s << "]" << std::endl;
#else 
      return;
#endif
}
/*读取和写文件内容*/
class FileUtil{
  public:
/*读取*/
inline static bool ReadFile(const std::string& filename, std::string& context) {
       LOG(INFO, "readfile name: " + filename);
       std::ifstream ifs(filename, std::ios::in);
       if (!ifs.is_open()) {
           LOG(ERROR, "file not open");
           return false;
       }
       while (!ifs.eof()) {
           std::string tmp;
           getline(ifs, tmp); 
           context += tmp + "\n";
       }
       ifs.close();
       LOG(INFO, context);
       return true;
}
  /*写出*/
inline static bool WriteFile(const std::string& filename, const std::string& context) {
    std::ofstream ost(filename, std::ios::out);
    if (!ost.is_open()) {
        LOG(ERROR, "file not create"); 
        return false;
    }
    ost << context;
    ost.close();
    return true;
}
};

class StringUtil{
    public:
      inline static void StringSplit(const std::string& body, std::vector<std::string>& v, const std::string& op) {
        boost::split(v, body, boost::is_any_of(op), boost::token_compress_on);
      }
      inline static std::string UrlEncode(std::string& body) {
          return UrlDecode(body);
      }
    private:
      static unsigned char ToHex(unsigned char x) 
      { 
          return  x > 9 ? x + 55 : x + 48; 
      }
       
      static unsigned char FromHex(unsigned char x) 
      { 
          unsigned char y;
          if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
          else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
          else if (x >= '0' && x <= '9') y = x - '0';
          else assert(0);
          return y;
      }
       
      static std::string UrlEncode(const std::string& str)
      {
          std::string strTemp = "";
          size_t length = str.length();
          for (size_t i = 0; i < length; i++)
          {
              if (isalnum((unsigned char)str[i]) || 
                  (str[i] == '-') ||
                  (str[i] == '_') || 
                  (str[i] == '.') || 
                  (str[i] == '~'))
                  strTemp += str[i];
              else if (str[i] == ' ')
                  strTemp += "+";
              else
              {
                  strTemp += '%';
                  strTemp += ToHex((unsigned char)str[i] >> 4);
                  strTemp += ToHex((unsigned char)str[i] % 16);
              }
          }
          return strTemp;
      }
       
      static std::string UrlDecode(const std::string& str)
      {
          std::string strTemp = "";
          size_t length = str.length();
          for (size_t i = 0; i < length; i++)
          {
              if (str[i] == '+') strTemp += ' ';
              else if (str[i] == '%')
              {
                  assert(i + 2 < length);
                  unsigned char high = FromHex((unsigned char)str[++i]);
                  unsigned char low = FromHex((unsigned char)str[++i]);
                  strTemp += high*16 + low;
              }
              else strTemp += str[i];
          }
          return strTemp;
      }
};
class UrlUtil{
      public:
      /*URLBody解析*/
      inline static bool UrlParse(const std::string& body, std::unordered_map<std::string, std::string>& kv_map) {
          /*1.先按&进行分割*/  
          std::vector<std::string> v;
          StringUtil::StringSplit(body, v, "&");      
          /*2.再按=进行获得kv*/
          for (auto& str :v) {
                std::vector<std::string> tmp;
                StringUtil::StringSplit(str, tmp, "=");
                if (tmp.size() != 2) {
                    LOG(ERROR, "Url parse ERROR");
                }
                /*Encode*/
                /*测试传输是否成功*/
                std::string _key = StringUtil::UrlEncode(tmp[0]);
                std::string _value = StringUtil::UrlEncode(tmp[1]);
                kv_map[_key] = _value; 
          }
          return true;
      }
      /*解析cookie*/
      inline static bool CookieParse(const std::string& body, Json::Value& cookieObj) {
            /*cookie以;分割,中间为=,末尾没有;*/
            /*1.先按;进行分割*/  
            std::vector<std::string> v;
            StringUtil::StringSplit(body, v, ";");      
            /*去除cookie中key-value之间的空格*/
            for (auto& i:v) {
              if (i[0] == ' '){
                  i.erase(i.begin()); 
              }
            }
            /*2.再按=进行获得kv*/
            for (auto& str :v) {
                std::vector<std::string> tmp;
                StringUtil::StringSplit(str, tmp, "=");
                if (tmp.size() != 2) {
                    LOG(ERROR, "Url parse ERROR");
                }
                /*Encode*/
                /*测试传输是否成功*/
                std::string _key = StringUtil::UrlEncode(tmp[0]);
                std::string _value = StringUtil::UrlEncode(tmp[1]);
                LOG(INFO, "key =" + _key);
                LOG(INFO, "value =" + _value);
                cookieObj[_key] = _value; 
            }
            return true;
      }
};
/*后期改到docker里运行,同时换一个权限小的用户跑进程*/
class SecurityUtil{
    public:
      static bool FindKeyWord(const Json::Value& req) {
             auto it = req["code"].asString().find("system");
             if (it != std::string::npos) {
                  return true;
             }
             else return false;
      }
};
